package com.zksite.nator.client.server;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import com.zksite.nator.client.config.MappingConfig;
import com.zksite.nator.client.server.handler.ConnectionWatchdog;
import com.zksite.nator.client.server.handler.NatorClientHandler;
import com.zksite.nator.common.config.Config;
import com.zksite.nator.common.context.SpringApplicationContext;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.HashedWheelTimer;

@Component
public class NatorClient implements Runnable, ApplicationListener<ApplicationEvent> {

	@Autowired
	private MappingConfig mappingConfig;

	protected final HashedWheelTimer timer = new HashedWheelTimer();

	private static final Logger LOGGER = LoggerFactory.getLogger(NatorClient.class);

	public void onApplicationEvent(ApplicationEvent event) {
		if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
			new Thread(this).start();
		}
	}

	public void run() {
		EventLoopGroup group = new NioEventLoopGroup();
		try {
			Bootstrap b = new Bootstrap();
			Config config = mappingConfig.getConfig();
			LOGGER.info("connect to server on {}:{}", config.getServer_ip(), config.getServer_port());
			final ConnectionWatchdog watchdog = new ConnectionWatchdog(b, timer,
					Integer.valueOf(config.getServer_port()), config.getServer_ip(), true) {
				@Override
				public ChannelHandler[] handlers() {
					return new ChannelHandler[] { //
							this, //
							new HttpRequestDecoder(), //
							new HttpResponseEncoder(), //
							new HttpObjectAggregator(65536), //
							new ChunkedWriteHandler(), //
							new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS), //
							SpringApplicationContext.getBean(NatorClientHandler.class) //
					};
				}

			};
			b.group(group) // 注册线程池
					.channel(NioSocketChannel.class) // 使用NioSocketChannel来作为连接用的channel类
					.remoteAddress(
							new InetSocketAddress(config.getServer_ip(), Integer.valueOf(config.getServer_port()))) // 绑定连接端口和host信息
					.handler(new ChannelInitializer<Channel>() {
						@Override
						protected void initChannel(Channel ch) throws Exception {
							ch.pipeline().addLast(watchdog.handlers());
						}

					});

			try {
				ChannelFuture cf = b.connect().sync();
				cf.channel().closeFuture().sync(); // 异步等待关闭连接channel
			} catch (InterruptedException e) {
				e.printStackTrace();
			} // 异步连接服务器

		} finally {
		}
	}

}
